/*
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
 * Copyright (c) 2013 China Beijing Armink <armink.ztl@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * File: $Id: mbrtu_m.c,v 1.60 2013/08/17 11:42:56 Armink Add Master Functions $
 */

/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"

/* ----------------------- Platform includes --------------------------------*/
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbframe.h"
#include "mbrtu.h"

#include "mbcrc.h"
#include "mbport.h"

#if MB_MASTER_RTU_ENABLED > 0
/* ----------------------- Defines ------------------------------------------*/
#define MB_SER_PDU_SIZE_MIN 4 /*!< Minimum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_CRC 2 /*!< Size of CRC field in PDU. */
#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */

/* ----------------------- Type definitions ---------------------------------*/
typedef enum {
    STATE_M_RX_INIT, /*!< Receiver is in initial state. */
    STATE_M_RX_IDLE, /*!< Receiver is in idle state. */
    STATE_M_RX_RCV, /*!< Frame is being received.  现在分词的被动语态 */
    STATE_M_RX_ERROR, /*!< If the frame is invalid. */
} eMBMasterRcvState;

typedef enum {
    STATE_M_TX_IDLE, /*!< Transmitter is in idle state. */
    STATE_M_TX_XMIT, /*!< Transmitter is in transfer state. */
    STATE_M_TX_XFWR, /*!< Transmitter is in transfer finish and wait receive state. */
} eMBMasterSndState;

/* ----------------------- Static variables ---------------------------------*/
static volatile eMBMasterSndState eSndState;
static volatile eMBMasterRcvState eRcvState;
// 这里包含了从站地址 就是从 从站地址快开始
static volatile UCHAR ucMasterRTUSndBuf[MB_PDU_SIZE_MAX]; // 除去从站地址 和 CRC校验
static volatile UCHAR ucMasterRTURcvBuf[MB_SER_PDU_SIZE_MAX]; // 接收用的缓冲区
static volatile USHORT usMasterSendPDULength;

static volatile UCHAR* pucMasterSndBufferCur; // 主站发送缓冲指针
static volatile USHORT usMasterSndBufferCount; // 主站发送缓冲计数器

static volatile USHORT usMasterRcvBufferPos;
static volatile BOOL xFrameIsBroadcast = FALSE;

static volatile eMBMasterTimerMode eMasterCurTimerMode; // 当前定时器的模式

/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode eMBMasterRTUInit(UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity)
{
    eMBErrorCode eStatus = MB_ENOERR;
    ULONG usTimerT35_50us; // 这个是50us的倍数

    ENTER_CRITICAL_SECTION();

    /* Modbus RTU uses 8 Databits. */
    if (xMBMasterPortSerialInit(ucPort, ulBaudRate, 8, eParity) != TRUE) { // 上面的函数会创建一个发送线程和发送事件
        eStatus = MB_EPORTERR;
    } else { // 当modbus用的串口初始化成功后
        /* If baudrate > 19200 then we should use the fixed timer values
         * t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
         */
        if (ulBaudRate > 19200) {
            usTimerT35_50us = 35; /* 1800us.    35*50==1750*/
        } else {
            /* The timer reload value for a character is given by:
             *
             * ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )  == Ticks_per_1s  *(11/Baudrate) == Ticks_per_1s *11 /Baudrate
             *             = 11 * Ticks_per_1s / Baudrate
             *             = 220000 / Baudrate  //
             * The reload for t3.5 is 1.5 times this value and similary
             * for t3.5.
             */
            usTimerT35_50us = (7UL * 220000UL) / (2UL * ulBaudRate); // 3.5*(220000UL/ulBaudRate)
        }
        if (xMBMasterPortTimersInit((USHORT)usTimerT35_50us) != TRUE) // 初始化时,时间就是3.5t
        { // 绑定超时函数
            eStatus = MB_EPORTERR;
        }
    }

    EXIT_CRITICAL_SECTION(); // 为毛得关闭调度器？？？

    return eStatus;
}

void eMBMasterRTUStart(void)
{
    ENTER_CRITICAL_SECTION();
    /* Initially the receiver is in the state STATE_M_RX_INIT. we start
     * the timer and if no character is received within t3.5 we change
     * to STATE_M_RX_IDLE. This makes sure that we delay startup of the
     * modbus protocol stack until the bus is free.
     */
    eRcvState = STATE_M_RX_INIT; // STATE_M_RX_INIT  接受处于初始化状态
    vMBMasterPortSerialEnable(TRUE, FALSE); // 接受开启,发送关闭
    vMBMasterPortTimersT35Enable(); // 时间到后eRcvState就会变为STATE_M_RX_IDLE //在超时函数中进行切换

    EXIT_CRITICAL_SECTION(); //
}

void eMBMasterRTUStop(void)
{
    ENTER_CRITICAL_SECTION();
    vMBMasterPortSerialEnable(FALSE, FALSE);
    vMBMasterPortTimersDisable(); // 这里是关闭定时器
    EXIT_CRITICAL_SECTION();
}

// 看完代码后得对整体有一个把控

eMBErrorCode
eMBMasterRTUReceive(UCHAR* pucRcvAddress, UCHAR** pucFrame, USHORT* pusLength)
{ // 在eMBMasterPoll()函数中接受事件为EV_MASTER_FRAME_RECEIVED时就会执行这个函数
    eMBErrorCode eStatus = MB_ENOERR;

    ENTER_CRITICAL_SECTION(); // 这里的 usMasterRcvBufferPos是从0开始的吗
    assert_param(usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX); // 接受缓冲区指针得始终在一定的范围内

    /* Length and CRC check */ //  MB_SER_PDU_SIZE_MIN 从站地址+功能码+ CRCL + CRCH
    if ((usMasterRcvBufferPos >= MB_SER_PDU_SIZE_MIN) && (usMBCRC16((UCHAR*)ucMasterRTURcvBuf, usMasterRcvBufferPos) == 0)) { // MB_SER_PDU_SIZE_MIN:包含从站地址+功能码+CRC(两字节)  //上面的usMasterRcvBufferPos指的是ucMasterRTURcvBuf的长度
        /* Save the address field. All frames are passed to the upper layed
         * and the decision if a frame is used is done there.
         */
        *pucRcvAddress = ucMasterRTURcvBuf[MB_SER_PDU_ADDR_OFF]; // 从设备地址

        /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
         * size of address field and CRC checksum.
         */
        *pusLength = (USHORT)(usMasterRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC); // 相当于减去3

        /* Return the start of the Modbus PDU to the caller. */
        *pucFrame = (UCHAR*)&ucMasterRTURcvBuf[MB_SER_PDU_PDU_OFF]; // 这里返回的其实是功能码
    } //
    else {
        eStatus = MB_EIO;
    }

    EXIT_CRITICAL_SECTION();
    return eStatus;
}

// typedef enum {
//     MB_ENOERR, /*!< no error. */
//     MB_ENOREG, /*!< illegal register address. */
//     MB_EINVAL, /*!< illegal argument. */
//     MB_EPORTERR, /*!< porting layer error. */
//     MB_ENORES, /*!< insufficient resources. */
//     MB_EIO, /*!< I/O error. */
//     MB_EILLSTATE, /*!< protocol stack in illegal state. */
//     MB_ETIMEDOUT /*!< timeout error occurred. */
// } eMBErrorCode; //这里是modbus错误码!

eMBErrorCode eMBMasterRTUSend(UCHAR ucSlaveAddress, const UCHAR* pucFrame, USHORT usLength)
{ //
    eMBErrorCode eStatus = MB_ENOERR;
    USHORT usCRC16;

    if (ucSlaveAddress > MB_MASTER_TOTAL_SLAVE_NUM) {
        return MB_EINVAL; /*!< illegal argument. */
    }

    ENTER_CRITICAL_SECTION(); // 关调度器

    /* Check if the receiver is still in idle state. If not we where to
     * slow with processing the received frame and the master sent another
     * frame on the network. We have to abort sending the frame.
     */
    if (eRcvState == STATE_M_RX_IDLE) // xMBMasterRTUTimerExpired()函数中变为了STATE_M_RX_IDLE状态
    { // 接收空闲,无事可做
        /* First byte before the Modbus-PDU is the slave address. */
        pucMasterSndBufferCur = (UCHAR*)pucFrame - 1; // pucFrame指向功能码  现在pucMasterSndBufferCur指向了待发送数据帧的首部(即从站地址)
        usMasterSndBufferCount = 1; //

        /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
        pucMasterSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress; // PDU部分已经在具体的功能线圈函数中写进去了
        usMasterSndBufferCount += usLength; // Address + (Function Code + data)(usLength)

        /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
        usCRC16 = usMBCRC16((UCHAR*)pucMasterSndBufferCur, usMasterSndBufferCount);
        ucMasterRTUSndBuf[usMasterSndBufferCount++] = (UCHAR)(usCRC16 & 0xFF); // CRC的低位
        ucMasterRTUSndBuf[usMasterSndBufferCount++] = (UCHAR)(usCRC16 >> 8); // CRC的高位
        // 这里pucMasterSndBufferCur实际指向ucMasterRTUSndBuf
        /* Activate the transmitter. */
        eSndState = STATE_M_TX_XMIT; // 已经处于发送状态
        vMBMasterPortSerialEnable(FALSE, TRUE); // 发送使能,接受使能  vMBMasterPortSerialEnable(TRUE, FALSE);  //实际的效果就是会调用 xMBMasterRTUTransmitFSM()
    } else {
        eStatus = MB_EIO;
    }
    EXIT_CRITICAL_SECTION();
    return eStatus;
}

BOOL xMBMasterRTUReceiveFSM(void) // 这个函数在接受中断里面调用  应该是每接受到一个字节就会调用一次这个函数
{
    BOOL xTaskNeedSwitch = FALSE;
    UCHAR ucByte;

    assert_param((eSndState == STATE_M_TX_IDLE) || (eSndState == STATE_M_TX_XFWR));
    // 上面就是排除 STATE_M_TX_XMIT状态,排除发送状态       STATE_M_TX_XFWR当发送完成后（同时会开启超时处理） 就会进入这个状态
    /* Always read the character. */
    (void)xMBMasterPortSerialGetByte((CHAR*)&ucByte); // 从串口读取一个字节

    switch (eRcvState) {
        /* If we have received a character in the init state we have to
         * wait until the frame is finished.
         */
    case STATE_M_RX_INIT: //  STATE_M_RX_INIT
        vMBMasterPortTimersT35Enable(); // 开启t3.5个时间  时间到了(表示确实没有一帧消息)那么eRcvState就变为了 STATE_M_RX_IDLE
        // xNeedPoll = xMBMasterPortEventPost(EV_MASTER_READY);  超时后就会产生这个玩意
        break; //

        /* In the error state we wait until all characters in the
         * damaged frame are transmitted.
         */
    case STATE_M_RX_ERROR:
        vMBMasterPortTimersT35Enable();
        break;

        /* In the idle state we wait for a new character. If a character
         * is received the t1.5 and t3.5 timers are started and the
         * receiver is in the state STATE_RX_RECEIVCE and disable early
         * the timer of respond timeout .
         */
    case STATE_M_RX_IDLE: // 只要接受到了一个字节就会进入到这里
        /* In time of respond timeout,the receiver receive a frame.
         * Disable timer of respond timeout and change the transmiter state to idle.
         */
        vMBMasterPortTimersDisable(); // 关闭超时计时器   rt_timer_stop()相当于这样
        eSndState = STATE_M_TX_IDLE; // 已经在接收了,那么发送就得处于空闲状态   此时就不会再报超时错误了,超时后也会认为是接收到了一个完整的帧

        usMasterRcvBufferPos = 0;
        ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte;
        eRcvState = STATE_M_RX_RCV; // 现在分词的被动语态

        /* Enable t3.5 timers. */
        vMBMasterPortTimersT35Enable(); // 相当于不断给定时器赋初始值
        //  xNeedPoll = xMBMasterPortEventPost(EV_MASTER_FRAME_RECEIVED);  超时后就会产生这个玩意儿
        break;

        /* We are currently receiving a frame. Reset the timer after
         * every character received. If more than the maximum possible
         * number of bytes in a modbus frame is received the frame is
         * ignored.
         */
    case STATE_M_RX_RCV:
        if (usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX) {
            ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte;
        } else {
            eRcvState = STATE_M_RX_ERROR; // 表明接收出现错误
        }
        vMBMasterPortTimersT35Enable(); // 相当于不断给定时器赋初始值
        break;
    }
    return xTaskNeedSwitch;
}

BOOL xMBMasterRTUTransmitFSM(void) // 在发送过程中会周期性的调用  线程接收到事件后就会执行这个函数
{ // 这个函数会在发送线程中调用  serial_soft_trans_irq(就是会在这个函数中调用)
    BOOL xNeedPoll = FALSE;

    assert_param(eRcvState == STATE_M_RX_IDLE); // 当前接受状态一定得是空闲的(否则就无法发送)  STATE_M_TX_XMIT
    //   eRcvState = STATE_M_RX_INIT;
    switch (eSndState) {
        /* We should not get a transmitter event if the transmitter is in
         * idle state.  */
    case STATE_M_TX_IDLE:
        /* enable receiver/disable transmitter. */
        vMBMasterPortSerialEnable(TRUE, FALSE); // 这里会执行  rt_event_recv()函数并且不用等待
        break; // 这里应该就是将RS485设置为接收状态

    case STATE_M_TX_XMIT: // 在eMBMasterRTUSend函数中已经被置位了
        /* check if we are finished.      发送假消息发送假指令来借刀杀人*/
        if (usMasterSndBufferCount != 0) { // usMasterSndBufferCount
            xMBMasterPortSerialPutByte((CHAR)*pucMasterSndBufferCur); // 这里就是串口发送函数 发送一个字节  会触发发送完成中断
            pucMasterSndBufferCur++; /* next byte in sendbuffer. */
            usMasterSndBufferCount--; // 我们高处见 ！！！！！！！！！！！！
        } else { // 这里应该是usMasterSndBufferCount为0的时候  //这里pucMasterSndBufferCur实际指向ucMasterRTUSndBuf
            xFrameIsBroadcast = (ucMasterRTUSndBuf[MB_SER_PDU_ADDR_OFF] == MB_ADDRESS_BROADCAST) ? TRUE : FALSE; // ucMasterRTUSndBuf
            /* Disable transmitter. This prevents another transmit buffer   //从站地址为0表示广播
             * empty interrupt. */
            vMBMasterPortSerialEnable(TRUE, FALSE); // 开启接受,关闭发送  发送是FALSE 相当于将多余发送 even给消解掉
            eSndState = STATE_M_TX_XFWR; // 发送完成,等待接受状态
            /* If the frame is broadcast ,master will enable timer of convert delay, 从机接收到广播后应该不会回复
             * else master will enable timer of respond timeout. */
            if (xFrameIsBroadcast == TRUE) { // convert delay 转换延迟
                vMBMasterPortTimersConvertDelayEnable(); // 这里还没搞懂
            } else { // respond timeout  响应超时
                vMBMasterPortTimersRespondTimeoutEnable();
            }
        } // 正常情况下,接受马上就会发生  如果接受没有发生,那么就会发生超时
        break;

    default:
        break;
    }

    return xNeedPoll;
}

BOOL xMBMasterRTUTimerExpired(void)
{ // 这个函数在软件定时器超时时,会被调用
    BOOL xNeedPoll = FALSE;

    switch (eRcvState) { // 判断接收状态   STATE_M_RX_INIT
        /* Timer t35 expired. Startup phase is finished. */
    case STATE_M_RX_INIT: // eRcvState = STATE_M_RX_INIT; 开启 t35之前设置的状态
        xNeedPoll = xMBMasterPortEventPost(EV_MASTER_READY); // 开启串口之后过了t35个时间
        break; // 会在eMBMasterPoll()中等待这个事件

        /* A frame was received and t35 expired. Notify the listener that
         * a new frame was received. */
    case STATE_M_RX_RCV: // STATE_M_RX_RCV  表明是一个新的帧  STATE_M_RX_RCV
        xNeedPoll = xMBMasterPortEventPost(EV_MASTER_FRAME_RECEIVED);
        break;

        /* An error occured while receiving the frame. */
    case STATE_M_RX_ERROR:
        vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA); // EV_ERROR_RECEIVE_DATA
        xNeedPoll = xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
        break;

        /* Function called in an illegal state. */
    default:
        assert_param(
            (eRcvState == STATE_M_RX_INIT) || (eRcvState == STATE_M_RX_RCV) || (eRcvState == STATE_M_RX_ERROR) || (eRcvState == STATE_M_RX_IDLE));
        break;
    }
    eRcvState = STATE_M_RX_IDLE; // MB_TMODE_CONVERT_DELAY

    switch (eSndState) { // 判断发送状态
        /* A frame was send finish and convert delay or respond timeout expired.
         * If the frame is broadcast,The master will idle,and if the frame is not
         * broadcast.Notify the listener process error.*/
    case STATE_M_TX_XFWR: // STATE_M_TX_XFWR  表示发送完成后 串口一个字节都没有收到 当然会发生超时
        if (xFrameIsBroadcast == FALSE) { // 单播会触发 EV_ERROR_RESPOND_TIMEOUT
            // 广播不会执行到这里
            vMBMasterSetErrorType(EV_ERROR_RESPOND_TIMEOUT);
            xNeedPoll = xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS); // 这里只是粗略的写
        } //
        break;
        /* Function called in an illegal state. */
    default:
        assert_param(
            (eSndState == STATE_M_TX_XFWR) || (eSndState == STATE_M_TX_IDLE));
        break;
    }

    eSndState = STATE_M_TX_IDLE;

    vMBMasterPortTimersDisable(); // 里面执行的就是 rt_timer_stop()函数
    /* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
    if (eMasterCurTimerMode == MB_TMODE_CONVERT_DELAY) { // MB_TMODE_CONVERT_DELAY
        // 这里表示  xFrameIsBroadcast == TRUE   也就是说广播时,一定会发生  convert_delay();
        xNeedPoll = xMBMasterPortEventPost(EV_MASTER_EXECUTE); // 具体的线圈发送函数发送完成后 会等待返回的事件
    }

    return xNeedPoll;
}

/* Get Modbus Master send RTU's buffer address pointer.*/
void vMBMasterGetRTUSndBuf(UCHAR** pucFrame)
{ // 这里返回的是从站的地址
    *pucFrame = (UCHAR*)ucMasterRTUSndBuf; // 这里面不包含从站地址和CRC
}

/* Get Modbus Master send PDU's buffer address pointer.*/
void vMBMasterGetPDUSndBuf(UCHAR** pucFrame)
{ //(*pucFrame)         ucMasterRTUSndBuf
    *pucFrame = (UCHAR*)&ucMasterRTUSndBuf[MB_SER_PDU_PDU_OFF]; // 指向功能码
}

/* Set Modbus Master send PDU's buffer length.*/
void vMBMasterSetPDUSndLength(USHORT SendPDULength)
{
    usMasterSendPDULength = SendPDULength;
}

/* Get Modbus Master send PDU's buffer length.*/
USHORT usMBMasterGetPDUSndLength(void)
{
    return usMasterSendPDULength;
}

/* Set Modbus Master current timer mode.*/
void vMBMasterSetCurTimerMode(eMBMasterTimerMode eMBTimerMode)
{
    eMasterCurTimerMode = eMBTimerMode;
}

/* The master request is broadcast? */
BOOL xMBMasterRequestIsBroadcast(void)
{
    return xFrameIsBroadcast;
}
#endif
